package raytracer.math;


public class Vector3d extends Tuple3d {
	
	public Vector3d() {
		this(0,0,0);
	}
	
	public Vector3d(double x,double y,double z) {
		super(x,y,z);
	}
	
	public Vector3d(Vector3d v3d) {
		super(v3d);
	}
	
	public double dot(Vector3d v3d) {
		return x*v3d.x+y*v3d.y+z*v3d.z;
	}
	
	public Vector3d cross(Vector3d v3d) {
		return new Vector3d(
				y*v3d.z-z*v3d.y,
				z*v3d.x-x*v3d.z,
				x*v3d.y-y*v3d.x
		);
	}
	
	public double length() {
		return Math.sqrt(x*x+y*y+z*z);
	}
	
	public void normalize() {
		double l=length();
		x/=l;
		y/=l;
		z/=l;
	}
	
	/**
	 * @note Maybe we need that for ambient occlusion (hemisphere rays)
	 * @param v
	 * @return
	 */
	public Vector3d getOrthogonal() {
		Vector3d u=new Vector3d();
		if (this.x==0)
			u.set(1,0,0);
		else {
			u.set(-this.y,this.x,0);
			u.normalize();
		}
		u.normalize();
		return u;
	}
	
	public static Vector3d getHemispherePoint(Vector3d x, Vector3d y, Vector3d z) {
		/*Vector3d randomVector=new Vector3d(Math.random(),Math.random(),Math.random());
		randomVector.normalize();
		if (randomVector.dot(y)<0)
			randomVector.negate();
		return randomVector;*/
		Vector3d xOnSphere=new Vector3d(x);
		double angle=Math.PI*Math.random()*2;
		double radius=Math.random();
		xOnSphere.scale(Math.cos(angle)*radius);
		Vector3d zOnSphere=new Vector3d(z);
		zOnSphere.scale(Math.sin(angle)*radius);
		Vector3d tempVector=new Vector3d(xOnSphere);
		tempVector.add(zOnSphere);
		double yValue=Math.sqrt(1-(tempVector.x*tempVector.x+tempVector.z*tempVector.z));
		Vector3d yOnSphere=new Vector3d(y);
		yOnSphere.scale(yValue);
		tempVector.add(yOnSphere);
		return tempVector;
	}
		
}
